/**
 * 
 */
package com.effectiv.gooruda.rest.api.service;

import java.util.List;

import jodd.cache.LFUCache;
import jodd.mail.CommonEmail;
import jodd.mail.Pop3Server;
import jodd.mail.Pop3SslServer;
import jodd.mail.ReceiveMailSession;
import jodd.mail.ReceivedEmail;
import jodd.mail.SendMailSession;
import jodd.mail.SmtpServer;
import jodd.mail.SmtpSslServer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;

import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.effectiv.gooruda.rest.api.domain.Email;
import com.effectiv.gooruda.rest.api.domain.EmailServerConfiguration;
import com.effectiv.gooruda.rest.api.exception.DuplicateDataException;
import com.effectiv.gooruda.rest.api.exception.NoDataFoundException;
import com.effectiv.gooruda.rest.api.operation.EmailOperations;
import com.effectiv.gooruda.security.rest.RESTSecurityUtil;

/**
 * @author Dhrubo
 * 
 */
@Component
public class EmailServiceImpl implements EmailOperations {

	@Autowired
	private MongoTemplate template;

	private final String EMAIL_CONFIG_COLLECTION_BASE = "c_email_config_";

	private LFUCache<String, SmtpServer> serverCache = new LFUCache<String, SmtpServer>(
			50, 600000);
	
	private LFUCache<String, Pop3Server> serverCachePop3 = new LFUCache<String, Pop3Server>(
			50, 600000);

	@Override
	public EmailServerConfiguration saveEmailServerConfiguration(EmailServerConfiguration config) {
		EmailServerConfiguration esc = findOneConfigurationByName(config.getName());
		if (esc != null) {
			throw new DuplicateDataException("Configuration with name - "
					+ config.getName() + " already exists.");
		}
		
		template.save(config,
				EMAIL_CONFIG_COLLECTION_BASE + RESTSecurityUtil.getAppId());
		
		return config;
	}

	@Override
	public EmailServerConfiguration findOneConfigurationByName(String name) {
		Query query = new Query();
		query.addCriteria(Criteria.where("name").is(name));

		return template.findOne(query, EmailServerConfiguration.class,
				EMAIL_CONFIG_COLLECTION_BASE + RESTSecurityUtil.getAppId());
	}

	@Override
	public List<EmailServerConfiguration> findAll() {
		return template.findAll(EmailServerConfiguration.class,
				EMAIL_CONFIG_COLLECTION_BASE + RESTSecurityUtil.getAppId());
	}

	@Override
	public void deleteConfigurationByName(String name) {
		Query query = new Query();
		query.addCriteria(Criteria.where("name").is(name));

		template.remove(query,
				EMAIL_CONFIG_COLLECTION_BASE + RESTSecurityUtil.getAppId());

	}

	@Async
	@Override
	public void send(String configName, Email email) {
		jodd.mail.Email e = jodd.mail.Email.create();
		e.from(email.getFrom()).setSubject(email.getSubject());
		e.setTo(email.getTo());
		e.setReplyTo(email.getFrom());
		e.setPriority(CommonEmail.PRIORITY_HIGH);

		if (email.isHtml()) {
			e.addHtml(email.getBody(), "UTF-8");
		} else {
			e.addText(email.getBody());
		}

		
		SmtpServer server = serverCache.get(configName);

		if (server == null) {
			EmailServerConfiguration config = findOneConfigurationByName(configName);
			
			if(config == null) {
				throw new NoDataFoundException("Email configuration not found with config name - " + configName);
			}
			
			if (config.isSSL()) {
				server = new SmtpSslServer(config.getHost(), config.getPort(),
						config.getUserName(), config.getPassword());
			} else {
				server = new SmtpServer(config.getHost(), config.getPort(),
						config.getUserName(), config.getPassword());
			}

		}

		SendMailSession session = server.createSession();
		session.open();
		session.sendMail(e);
		session.close();
	}

	@Override
	public ReceivedEmail[] receive(String configName) {
		Pop3Server server = serverCachePop3.get(configName);

		if (server == null) {
			EmailServerConfiguration config = findOneConfigurationByName(configName);
			
			if(config == null) {
				throw new NoDataFoundException("Email configuration not found with config name - " + configName);
			}
			
			if (config.isSSL()) {
				server = new Pop3SslServer(config.getHost(), config.getPort(),
						config.getUserName(), config.getPassword());
			} else {
				server = new Pop3Server(config.getHost(), config.getPort(),
						config.getUserName(), config.getPassword());
			}

		}
		
		ReceiveMailSession session = server.createSession();
		session.open();
		ReceivedEmail[] emails = session.receiveEmail(false);
		session.close();
		return emails;
	}

}
